package com.changgou.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.changgou.entity.Result;
import com.changgou.goods.feign.SkuFeign;
import com.changgou.goods.pojo.Sku;
import com.changgou.search.dao.SkuEsMapper;
import com.changgou.search.pojo.SkuInfo;
import com.changgou.search.service.SkuService;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class SkuServiceImpl implements SkuService {

    @Autowired
    private SkuEsMapper skuEsMapper;

    @Autowired
    private SkuFeign skuFeign;

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    /**
     * 调用商品微服务,查询所有正常状态的sku数据,并导入到es中
     */
    @Override
    public void importEs() {
        // 将sku数据都查询出来
        Result<List<Sku>> skuList = skuFeign.findByStatus("1");
        // 将查询出来的数据导入的es中
        // 将skulist装换成List<SKuinfo>
        List<Sku> skuListData = skuList.getData();
        String jsonString = JSON.toJSONString(skuListData);
        List<SkuInfo> skuinfoList = JSON.parseArray(jsonString, SkuInfo.class);
        for (SkuInfo skuInfo : skuinfoList) {
            Map<String, Object> specMap = JSON.parseObject(skuInfo.getSpec());
            skuInfo.setSpecMap(specMap);
        }
        skuEsMapper.saveAll(skuinfoList);
    }

    /**
     * 搜索
     *
     * @param searchMap
     * @return
     */
    @Override
    public Map search(Map<String, String> searchMap) {
        // 1. 获取关键字的值
        String keywords = searchMap.get("keywords");
        if (StringUtils.isEmpty(keywords)) {
            keywords = "华为";
        }
        // 2. 创建查询对象的构建对象
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        // 3.设置查询的条件
        // 设置分组条件 商品分类
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuCategorygroup").field("categoryName").size(50));

        // 设置分组条件 商品品牌
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuBrandgroup").field("brandName").size(50));

        // 设置分组条件 商品的规格
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("skuSpecgroup").field("spec.keyword").size(100));


        // 设置高亮条件
        nativeSearchQueryBuilder.withHighlightFields(new HighlightBuilder.Field("name"));
        nativeSearchQueryBuilder.withHighlightBuilder(new HighlightBuilder().preTags("<em style=\"color:red\">").postTags("</em>"));

        // 设置主关键字查询
        // nativeSearchQueryBuilder.withQuery(QueryBuilders.matchQuery("name", keywords));
        nativeSearchQueryBuilder.withQuery(QueryBuilders.multiMatchQuery(keywords,"name", "brandName", "categoryName"));

        // 构建查询条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if (StringUtils.isNotEmpty(searchMap.get("brand"))) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("brandName", searchMap.get("brand"))); // 品牌条件
        }
        if (StringUtils.isNotEmpty(searchMap.get("category"))) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("categoryName", searchMap.get("category"))); // 分类条件
        }
        if (searchMap != null) {
            for (String key : searchMap.keySet()) {
                // 前端以spec_规格名=规格选项值 的方式传递过来,后台循环遍历操作既可  specMap.屏幕尺寸.keyword
                if (key.startsWith("spec_")) {
                    boolQueryBuilder.filter(QueryBuilders.termQuery("specMap." + key.substring(5) + ".keyword", searchMap.get(key)));
                }
            }
        }

        // 价格过滤条件设置 前端可能穿过来的是: 0-500
        String price = searchMap.get("price");
        if (StringUtils.isNotEmpty(price)) {
            String[] split = price.split("-");
            if (!split[1].equalsIgnoreCase("*")) {
                boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").from(split[0]).to(split[1], true));
            } else {
                boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(split[0]));
            }
        }

        // 构建分页查询
        Integer pageNum = 1;
        if(StringUtils.isNotEmpty(searchMap.get("pageNum"))) {
            try {
                pageNum = Integer.valueOf(searchMap.get("pageNum"));
            } catch (NumberFormatException e) {
                e.printStackTrace();
                pageNum = 1;
            }
        }
        Integer pageSize = 30;
        nativeSearchQueryBuilder.withPageable(PageRequest.of(pageNum - 1, pageSize));

        // 构建排序查询
        String sortRule = searchMap.get("sortRule");
        String sortField = searchMap.get("sortField");
        if(!StringUtils.isEmpty(sortField) && !StringUtils.isEmpty(sortRule)) {
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(sortField)
                    .order(sortRule.equalsIgnoreCase("DESC") ? SortOrder.DESC : SortOrder.ASC));
        }

        // 设置过滤条件
        nativeSearchQueryBuilder.withFilter(boolQueryBuilder);
        // 4.构建查询对象
        NativeSearchQuery query = nativeSearchQueryBuilder.build();

        // 5. 执行查询
        AggregatedPage<SkuInfo> skupages = elasticsearchTemplate.queryForPage(query, SkuInfo.class, new SearchResultMapperImpl());


        // 获取分组结果 商品分类
        StringTerms stringTerms = (StringTerms) skupages.getAggregation("skuCategorygroup");
        // 获取分组结果商品品牌
        StringTerms stringTermsBrand = (StringTerms) skupages.getAggregation("skuBrandgroup");
        // 获取规格的分组结果
        StringTerms stringTermsSpec = (StringTerms) skupages.getAggregation("skuSpecgroup");


        // 获取分类的结果数据
        List<String> categoryList = getStringsCategoryList(stringTerms);
        // 获取品牌的规格数据
        List<String> brandList = getStringsBrandList(stringTermsBrand);
        // 获取规格的结果数据
        Map<String, Set<String>> specMap = getStringSetMap(stringTermsSpec);

        // 6. 返回结果
        Map map = new HashMap();
        map.put("pageNum", pageNum);
        map.put("pageSize", pageSize);
        map.put("categoryList", categoryList);
        map.put("specMap", specMap);
        map.put("brandList", brandList);
        map.put("rows", skupages.getContent());
        map.put("total", skupages.getTotalElements());
        map.put("totalPages", skupages.getTotalPages());
        return map;
    }

    /**
     * 获取规格分组的方法
     *
     * @param stringTermsSpec
     * @return
     */
    private Map<String, Set<String>> getStringSetMap(StringTerms stringTermsSpec) {
        Map<String, Set<String>> sepcMap = new HashMap<>();
        Set<String> specList = new HashSet<>();
        if (stringTermsSpec != null) {
            for (StringTerms.Bucket bucket : stringTermsSpec.getBuckets()) {
                specList.add(bucket.getKeyAsString());
            }
        }
        System.out.println("specList: " + specList);
        for (String specJson : specList) {
            Map<String, String> map = JSON.parseObject(specJson, Map.class);
            for (Map.Entry<String, String> entry : map.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                Set<String> specValues = sepcMap.get(key);
                if (specValues == null) {
                    specValues = new HashSet<>();
                }
                specValues.add(value);
                sepcMap.put(key, specValues);
            }
        }
        return sepcMap;
    }

    /**
     * 获取品牌的列表
     *
     * @param stringTermsBrand
     * @return
     */
    private List<String> getStringsBrandList(StringTerms stringTermsBrand) {
        List<String> brandList = new ArrayList<>();
        if (brandList != null) {
            for (StringTerms.Bucket bucket : stringTermsBrand.getBuckets()) {
                brandList.add(bucket.getKeyAsString()); // 品牌的值
            }
        }
        return brandList;
    }

    /**
     * 获取分类列表
     *
     * @param stringTerms
     * @return
     */
    private List<String> getStringsCategoryList(StringTerms stringTerms) {
        List<String> categoryList = new ArrayList<>();
        if (categoryList != null) {
            for (StringTerms.Bucket bucket : stringTerms.getBuckets()) {
                String keyAsString = bucket.getKeyAsString(); // 分组的值
                categoryList.add(keyAsString);
            }
        }
        return categoryList;
    }
}
